package cn.hd.authorService.aop;

import cn.hd.authorService.service.log.SystemLogService;
import cn.hd.commonService.annotations.LogAnnotation;
import cn.hd.commonService.entity.SystemLog;
import cn.hd.commonService.exception.CustomException;
import cn.hd.commonService.utils.DateUtils;
import cn.hd.commonService.vo.Result;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

/**
 * created by dsl on 2022/8/5
 * 日志切面类
 */
@Component
@Aspect
@Slf4j
public class LogAopAction {
    /**
     * 统计请求的处理时间
     */
    ThreadLocal<Long> startTime = new ThreadLocal<>();
    @Autowired
    private SystemLogService systemLogService;

    @Pointcut("@annotation(cn.hd.commonService.annotations.LogAnnotation)")
    public void LogAopAction() {}

    /**
     * @methodName：exceptionLogPoinCut
     * @description：设置操作异常切入点记录异常日志 扫描所有controller包下操作
     * @author：tanyp
     * @dateTime：2021/11/18 14:22
     * @Params： []
     * @Return： void
     * @editNote：
     */
    @Pointcut("execution(* cn.hd.*.controller..*.*(..))")
    public void exceptionLogPointCut() {
    }


    /**
     * @CreatedBy dsl
     * 请求前的日志处理
     */
    @Before("LogAopAction()")
    public void before(){
        startTime.set(System.currentTimeMillis());
    }

    @AfterReturning(value = "LogAopAction()",returning ="keys")
    public void doAfterReturning(JoinPoint joinPoint,Object keys) throws Exception{
        SystemLog systemLog = packageData(joinPoint);
        if (StrUtil.isEmptyIfStr(keys)){
            systemLog.setResult(null);
        }else {
            //获取请求结果
            systemLog.setResult(JSONUtil.parseObj(keys).toString());
        }
        long endTime = System.currentTimeMillis();
        //设置消耗时间
        systemLog.setSpendTime((endTime-startTime.get())/1000.0);
        //设置结束时间
        systemLog.setEndTime(endTime);
        //保存日志信息
        systemLogService.save(systemLog);
        systemLog.setStartTimeDesc(DateUtils.longToStr(startTime.get()));
        systemLog.setEndTimeDesc(DateUtils.longToStr(endTime));
        log.info("{}", JSONUtil.parse(systemLog));

    }
    @AfterThrowing(pointcut = "exceptionLogPointCut()", throwing = "e")
    public void doAfterThrowing(JoinPoint joinPoint,Exception e) throws Exception{
        log.error("异常信息：{}",e);
        long endTime = System.currentTimeMillis();
        SystemLog systemLog = packageData(joinPoint);
        //设置消耗时间
        systemLog.setSpendTime((endTime-startTime.get())/1000.0);
        //设置结束时间
        systemLog.setEndTime(endTime);

        Result error = Result.defineError(CustomException.cloneException(e));
        systemLog.setResult(error.toString());
        systemLogService.save(systemLog);
        systemLog.setEndTimeDesc(DateUtils.longToStr(endTime));
        log.info("{}",JSONUtil.parse(systemLog));
    }

    public SystemLog packageData(JoinPoint joinPoint) throws Exception{
        SystemLog systemLog = new SystemLog();
        systemLog.setRecordId(UUID.randomUUID().toString());
        startTime.set(System.currentTimeMillis());
        //获取当前请求对象
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        //获取请求方法信息
        getMethodInfo(joinPoint,systemLog);
        //获取请求时间
        systemLog.setStartTime(startTime.get());

        //获取请求的url
        systemLog.setUrl(request.getRequestURI());
        //获取当前登录用户
        systemLog.setUserName(request.getRemoteUser());
        //获取请求Ip
        String Ip = InetAddress.getLocalHost().getHostAddress();
        systemLog.setIp(Ip);
        return systemLog;
    }
    /**
     *
     * @param joinPoint
     * @param systemLog
     * @throws ClassNotFoundException
     * 获取方法请求方法相关的信息
     */
    public void getMethodInfo(JoinPoint joinPoint,SystemLog systemLog) throws ClassNotFoundException {
        String methodName = joinPoint.getSignature().getName();
        String targetName = joinPoint.getTarget().getClass().getName();
        Class targetClass = Class.forName(targetName);
        Method[] methods = targetClass.getMethods();
        for (Method method : methods){
            if(method.getName().equals(methodName)){
                LogAnnotation logAnnotation = method.getAnnotation(LogAnnotation.class);//注解类
                systemLog.setMethodName(logAnnotation.methodName());
                systemLog.setMethodDesc(logAnnotation.methodDesc());
                systemLog.setMethodType(logAnnotation.methodType().getType());
                systemLog.setParameter(getRequestParameterS(joinPoint,method));
                break;
            }
        }
    }

    /**
     * @CreatedBy dsl
     * 设置请求参数
     */
    private String getRequestParameterS(JoinPoint joinPoint, Method method) {
        //参数转换
        DefaultParameterNameDiscoverer discoverer = new DefaultParameterNameDiscoverer();
        //获取方法的参数名
        String[] parameterNames = discoverer.getParameterNames(method);
        //获取方法的参数值
        List<Object> list = Convert.toList(Object.class, joinPoint.getArgs());
        //参数处理
        Map<String,Object> parameterData = new HashMap<>();
        for (int i = 0; i < parameterNames.length; i++) {
            parameterData.put(parameterNames[i],list.get(i));
        }
        return JSONUtil.parse(parameterData).toString();
    }
}
